home *** CD-ROM | disk | FTP | other *** search
/ Megadoom II / MEGADOOM II - iso.7z / MEGADOOM II.ISO / doom / editors / wadfile / warm11 / wadio.c < prev    next >
C/C++ Source or Header  |  1994-12-21  |  25KB  |  623 lines

  1. /******************************************************************************
  2.     MODULE:        WADIO.C
  3.     WRITTEN BY:    Robert Fenske, Jr. (rfenske@swri.edu)
  4.                 Southwest Research Institute
  5.                 Electromagnetics Division
  6.                 6220 Culebra
  7.                 San Antonio, Texas 78238-5166
  8.     CREATED:    May  1994
  9.     DESCRIPTION:    This module contains routines to read and write DOOM-
  10.             related IWAD, PWAD, and VERDA patch files.
  11.  
  12.             There is a number of byte swapping calls used in the
  13.             SunOS case; these calls are ugly, but necessary since
  14.             the WAD files store data in little-endian order.
  15.  
  16.             DOOM is a trademark of id Software, Inc.
  17. ******************************************************************************/
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include "dmglobal.i"
  23.  
  24. #if defined(sun) && !defined(BSWAP)        /* anything big-endian (like */
  25. #define BSWAP        1            /* Suns) needs bytes swapped */
  26. #endif
  27.  
  28. #if defined(BSWAP)
  29. #define bswapw(v)    ((unsigned short)((((v)>>8)&0xFF) | ((v)<<8)))
  30. #define bswapl(v)    ((unsigned long)((((v)>>24)&0x000000FFL) | \
  31.                              (((v)>> 8)&0x0000FF00L) | \
  32.                              (((v)<< 8)&0x00FF0000L) | \
  33.                              ( (v)<<24)))
  34. #else
  35. #define bswapw(v)    (v)
  36. #define bswapl(v)    (v)
  37. #endif
  38.  
  39. #define is_type(n,t)    (strncmp((n),mapresrc[t],sizeof(n)) == 0)
  40.  
  41. local char mapresrc[][9] = {            /* resource name in dir */
  42.     "", "THINGS", "LINEDEFS", "SIDEDEFS", "VERTEXES", "SEGS",
  43.     "SSECTORS", "NODES", "SECTORS", "REJECT", "BLOCKMAP"
  44. };
  45. local int mapresiz[] = {            /* item size in resource */
  46.     1, sizeof(DOOM_THING), sizeof(DOOM_LINE),
  47.     sizeof(DOOM_SIDE), sizeof(DOOM_VERT),
  48.     sizeof(DOOM_SEGS), sizeof(DOOM_SSECTOR),
  49.     sizeof(DOOM_NODE), sizeof(DOOM_SECTOR),
  50.     sizeof(DOOM_REJECT), sizeof(DOOM_BLOCKMAP)
  51. };
  52.  
  53.  
  54. /******************************************************************************
  55.     ROUTINE:    wad_bswap(winfo,resource)
  56.     WRITTEN BY:    Robert Fenske, Jr.
  57.     CREATED:    May  1994
  58.     DESCRIPTION:    This routine swaps the bytes in the short integer
  59.             fields of the various resources.  This is necessary
  60.             since the data files store integers in Intel little-
  61.             endian order, while all real systems use big-endian
  62.             order.
  63. ******************************************************************************/
  64. #if defined(BSWAP)
  65. #if defined(ANSI_C)
  66. local void wad_bswap(register WAD_INFO *winfo, int resource)
  67. #else
  68. local void wad_bswap(winfo,resource)
  69. register WAD_INFO *winfo;
  70. int resource;
  71. #endif
  72. {
  73.   short *data = (short *)winfo->data[resource];    /* where data is */
  74.   DOOM_SIDE *sides = (DOOM_SIDE *)data;
  75.   DOOM_SECTOR *sects = (DOOM_SECTOR *)data;
  76.   int cnt = resource_count(&winfo->dir[resource]);
  77.   int type;
  78.   register int d, w;
  79.  
  80.   if (data != NULL) {
  81.     for (type = 0; type < numelm(mapresrc); type++)
  82.       if (is_type(winfo->dir[resource].name,type)) break;
  83.     switch (type) {
  84.        case THINGS:
  85.        case LINES:
  86.        case VERTS:
  87.        case SEGS:
  88.        case SSECTS:
  89.        case NODES:
  90.        case BLKMAPS:
  91.         for (d = 0; d < cnt; d++)
  92.           for (w = 0; w < mapresiz[type]/2; w++)
  93.             data[d*mapresiz[type]/2+w] = bswapw(data[d*mapresiz[type]/2+w]);
  94.       bcase SIDES:                /* only swap integer fields */
  95.         for (d = 0; d < cnt; d++) {
  96.           sides[d].image_xoff = bswapw(sides[d].image_xoff);
  97.           sides[d].image_yoff = bswapw(sides[d].image_yoff);
  98.           sides[d].sectndx = bswapw(sides[d].sectndx);
  99.         }
  100.       bcase SECTS:                /* only swap integer fields */
  101.         for (d = 0; d < cnt; d++) {
  102.           sects[d].floor_ht = bswapw(sects[d].floor_ht);
  103.           sects[d].ceil_ht = bswapw(sects[d].ceil_ht);
  104.           sects[d].light_lvl = bswapw(sects[d].light_lvl);
  105.           sects[d].property = bswapw(sects[d].property);
  106.           sects[d].line_tag = bswapw(sects[d].line_tag);
  107.         }
  108.       bcase REJECTS:                /* don't have to swap this */
  109.         ;
  110.       bdefault:                    /* something else--no swap */
  111.         ;
  112.     }
  113.   }
  114. }
  115. #endif
  116.  
  117.  
  118. /******************************************************************************
  119.     ROUTINE:    resource_update(winfo,entry,data,count)
  120.     WRITTEN BY:    Robert Fenske, Jr.
  121.     CREATED:    June 1994
  122.     DESCRIPTION:    This routine assigns the input data to the specified
  123.             entry.  If the entry already has data, it is freed
  124.             first.  The changed flag is set to TRUE.
  125. ******************************************************************************/
  126. #if defined(ANSI_C)
  127. void resource_update(register WAD_INFO *winfo, int entry, void *data,
  128.                      long count)
  129. #else
  130. void resource_update(winfo,entry,data,count)
  131. register WAD_INFO *winfo;
  132. int entry;
  133. void *data;
  134. long count;
  135. #endif
  136. {
  137.   register int type;
  138.  
  139.   if ((char *)data != winfo->data[entry]) blockfree(winfo->data[entry]);
  140.   winfo->data[entry] = (char *)data;
  141.   for (type = 0; type < numelm(mapresrc); type++)
  142.     if (is_type(winfo->dir[entry].name,type)) break;
  143.   if (type < numelm(mapresrc)) winfo->dir[entry].nbytes = count*mapresiz[type];
  144.   else                         winfo->dir[entry].nbytes = count;
  145.   winfo->count[entry] = count;
  146.   winfo->changed[entry] = TRUE;
  147. }
  148.  
  149.  
  150. /******************************************************************************
  151.     ROUTINE:    resource_count(entry)
  152.     WRITTEN BY:    Robert Fenske, Jr.
  153.     CREATED:    June 1994
  154.     DESCRIPTION:    This routine gets the count of the number of items in
  155.             the input directory entry (resource).  If the entry
  156.             is not associated with map level data, the number of
  157.             items is simply the byte count.
  158. ******************************************************************************/
  159. #if defined(ANSI_C)
  160. int resource_count(register DIR_ENTRY *entry)
  161. #else
  162. int resource_count(entry)
  163. register DIR_ENTRY *entry;
  164. #endif
  165. {
  166.   int count = 0;
  167.   register int type;
  168.  
  169.   if (entry != NULL) {
  170.     for (type = 0; type < numelm(mapresrc); type++)
  171.       if (is_type(entry->name,type)) break;
  172.     if (type < numelm(mapresrc)) count = entry->nbytes/mapresiz[type];
  173.     else                         count = entry->nbytes;
  174.   }
  175.   return count;
  176. }
  177.  
  178.  
  179. /******************************************************************************
  180.     ROUTINE:    patch_read(winfo,entry,resources_needed)
  181.     WRITTEN BY:    Robert Fenske, Jr.
  182.     CREATED:    May  1994
  183.     DESCRIPTION:    This routine reads a VERDA patch file.  It reads the
  184.             file twice; the first time is to obtain the sizes of
  185.             each of the resources.  The input resources_needed is
  186.             ignored--everything in the patch file is read.  Also,
  187.             only one level's data is stored in a patch file.
  188. ******************************************************************************/
  189. #if defined(ANSI_C)
  190. boolean patch_read(register WAD_INFO *winfo, int entry, long resources_needed)
  191. #else
  192. boolean patch_read(winfo,entry,resources_needed)
  193. register WAD_INFO *winfo;
  194. int entry;
  195. long resources_needed;
  196. #endif
  197. {
  198.   char str[256];
  199.   int type;
  200.   DOOM_THING *things;
  201.   DOOM_LINE *lines;
  202.   DOOM_SIDE *sides;
  203.   DOOM_VERT *verts;
  204.   DOOM_SEGS *segs;
  205.   DOOM_SSECTOR *ssecs;
  206.   DOOM_NODE *nodes;
  207.   DOOM_SECTOR *sects;
  208.   register int k;
  209.  
  210.   if (winfo->head.count <= entry)        /* can't read beyond count */
  211.     return FALSE;
  212.   for (k = 0; k < ALL; k++)
  213.     winfo->count[k] = 0;
  214.   rewind(winfo->fp);
  215.   for (k = 0; fgets(str,sizeof str,winfo->fp) != NULL; ) {/* get counts */
  216.     if (str[0] == ';' || str[0] == '#')        /* skip any comments */
  217.       continue;
  218.     if (k == 0) {
  219.       k = sscanf(str," %d %d %d %lf",&winfo->ep,&winfo->mp,&type,&winfo->ver);
  220.       continue;
  221.     }
  222.     k = str[0] != '%';
  223.     if (k) winfo->count[type]++;
  224.   }
  225.   for (k = 0; k < ALL; k++)
  226.     if ((resources_needed & (1L<<k)) && winfo->count[k] > 0) {
  227.       blockfree(winfo->data[k]);
  228.       winfo->dir[k].nbytes = winfo->count[k]*mapresiz[k];
  229.       winfo->data[k] = blockmem(char,winfo->dir[k].nbytes);
  230.     }
  231.   things = (DOOM_THING *)winfo->data[THINGS];
  232.   lines  = (DOOM_LINE *)winfo->data[LINES];
  233.   sides  = (DOOM_SIDE *)winfo->data[SIDES];
  234.   verts  = (DOOM_VERT *)winfo->data[VERTS];
  235.   segs   = (DOOM_SEGS *)winfo->data[SEGS];
  236.   ssecs  = (DOOM_SSECTOR *)winfo->data[SSECTS];
  237.   nodes  = (DOOM_NODE *)winfo->data[NODES];
  238.   sects  = (DOOM_SECTOR *)winfo->data[SECTS];
  239.   rewind(winfo->fp);
  240.   for (k = 0; fgets(str,sizeof str,winfo->fp) != NULL; ) {
  241.     if (str[0] == ';' || str[0] == '#')        /* skip any comments */
  242.       continue;
  243.     if (k == 0) {
  244.       k = sscanf(str," %d %d %d %lf",&winfo->ep,&winfo->mp,&type,&winfo->ver);
  245.       continue;
  246.     }
  247.     if (!(resources_needed & (1L << type)))
  248.       continue;
  249.     switch (type) {
  250.       case THINGS:                /* THINGS */
  251.     sscanf(str,"%*d %4hx %4hx %3hd %4hx %4hx",
  252.                &things->x,&things->y,&things->angle,&things->item,
  253.                &things->flag);
  254.         things++;
  255.       bcase LINES:                /* LINES */
  256.     sscanf(str,"%*d %4hx %4hx %4hx %4hx %4hx %4hx %4hx",
  257.                &lines->fndx,&lines->tndx,&lines->flag,&lines->action_flag,
  258.                &lines->sect_tag,&lines->rsidndx,&lines->lsidndx);
  259.         lines++;
  260.       bcase SIDES:                /* SIDES */
  261.     sscanf(str,"%*d %4hx %4hx %8c %8c %8c %4hx",
  262.                &sides->image_xoff,&sides->image_yoff,
  263.                sides->lwall,sides->uwall,sides->nwall,&sides->sectndx);
  264.         while (sides->lwall[min(8,strlen(sides->lwall))-1] == ' ')
  265.           sides->lwall[min(8,strlen(sides->lwall))-1] = '\0';
  266.         while (sides->uwall[min(8,strlen(sides->uwall))-1] == ' ')
  267.           sides->uwall[min(8,strlen(sides->uwall))-1] = '\0';
  268.         while (sides->nwall[min(8,strlen(sides->nwall))-1] == ' ')
  269.           sides->nwall[min(8,strlen(sides->nwall))-1] = '\0';
  270.         sides++;
  271.       bcase VERTS:                /* VERTEXES */
  272.     sscanf(str,"%*d %4hx %4hx",&verts->x,&verts->y);
  273.         verts++;
  274.       bcase SEGS:                /* SEGS */
  275.         sscanf(str,"%*d %4hx %4hx %4hx %4hx %4hx %4hx",
  276.                &segs->fndx,&segs->tndx,&segs->angle,&segs->lndx,&segs->sndx,
  277.                &segs->loffset);
  278.         segs++;
  279.       bcase SSECTS:                /* SSECTORS */
  280.         sscanf(str,"%*d %4hx %4hx",&ssecs->count,&ssecs->sndx);
  281.         ssecs++;
  282.       bcase NODES:                /* NODES */
  283.         sscanf(str,"%*d \
  284. %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx %4hx",
  285.                &nodes->x,&nodes->y,&nodes->xdel,&nodes->ydel,
  286.                &nodes->rymax,&nodes->rymin,&nodes->rxmin,&nodes->rxmax,
  287.                &nodes->lymax,&nodes->lymin,&nodes->lxmin,&nodes->lxmax,
  288.                &nodes->nndx[0],&nodes->nndx[1]);
  289.         nodes++;
  290.       bcase SECTS:                /* SECTORS */
  291.     sscanf(str,"%*d %4hx %4hx %8c %8c %4hx %4hx %4hx",
  292.                §s->floor_ht,§s->ceil_ht,sects->floor_desc,
  293.                sects->ceil_desc,§s->light_lvl,§s->property,
  294.                §s->line_tag);
  295.         while (sects->floor_desc[min(8,strlen(sects->floor_desc))-1] == ' ')
  296.           sects->floor_desc[min(8,strlen(sects->floor_desc))-1] = '\0';
  297.         while (sects->ceil_desc[min(8,strlen(sects->ceil_desc))-1] == ' ')
  298.           sects->ceil_desc[min(8,strlen(sects->ceil_desc))-1] = '\0';
  299.         sects++;
  300.     }
  301.     k = str[0] != '%';
  302.   }
  303.   winfo->ep++; winfo->mp++;
  304.   return TRUE;
  305. }
  306.  
  307.  
  308. /******************************************************************************
  309.     ROUTINE:    patch_write(oinfo,winfo)
  310.     WRITTEN BY:    Robert Fenske, Jr.
  311.     CREATED:    May  1994
  312.     DESCRIPTION:    This routine writes a VERDA patch file.  Only one
  313.             level's data is stored in a patch file.
  314. ******************************************************************************/
  315. #if defined(ANSI_C)
  316. boolean patch_write(register WAD_INFO *oinfo, register WAD_INFO *winfo)
  317. #else
  318. boolean patch_write(oinfo,winfo)
  319. register WAD_INFO *oinfo, *winfo;
  320. #endif
  321. {
  322.   DOOM_THING *things = (DOOM_THING *)winfo->data[THINGS];
  323.   DOOM_LINE *lines = (DOOM_LINE *)winfo->data[LINES];
  324.   DOOM_SIDE *sides = (DOOM_SIDE *)winfo->data[SIDES];
  325.   DOOM_VERT *verts = (DOOM_VERT *)winfo->data[VERTS];
  326.   DOOM_SEGS *segs = (DOOM_SEGS *)winfo->data[SEGS];
  327.   DOOM_SSECTOR *ssecs = (DOOM_SSECTOR *)winfo->data[SSECTS];
  328.   DOOM_NODE *nodes = (DOOM_NODE *)winfo->data[NODES];
  329.   DOOM_SECTOR *sects = (DOOM_SECTOR *)winfo->data[SECTS];
  330.   register int k;
  331.  
  332.   fprintf(oinfo->fp,"%d %d %d %4.2f\r\n",
  333.           --winfo->ep,--winfo->mp,THINGS,winfo->ver);
  334.   for (k = 0; k < winfo->count[THINGS]; k++)
  335.     fprintf(oinfo->fp,"%03d %04x %04x %03d %04x %02x\r\n",k,
  336.             (ushort)things[k].x,(ushort)things[k].y,things[k].angle,
  337.             things[k].item,things[k].flag);
  338.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  339.           winfo->ep,winfo->mp,LINES,winfo->ver);
  340.   for (k = 0; k < winfo->count[LINES]; k++)
  341.     fprintf(oinfo->fp,"%03d %04x %04x %04x %04x %04x %04x %04x\r\n",k,
  342.             lines[k].fndx,lines[k].tndx,
  343.             (ushort)lines[k].flag,(ushort)lines[k].action_flag,
  344.             (ushort)lines[k].sect_tag,
  345.             (ushort)lines[k].rsidndx,(ushort)lines[k].lsidndx);
  346.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  347.           winfo->ep,winfo->mp,SIDES,winfo->ver);
  348.   for (k = 0; k < winfo->count[SIDES]; k++)
  349.     fprintf(oinfo->fp,"%03d %04x %04x %-8.8s %-8.8s %-8.8s %03x\r\n",k,
  350.             (ushort)sides[k].image_xoff,(ushort)sides[k].image_yoff,
  351.             sides[k].lwall,sides[k].uwall,sides[k].nwall,sides[k].sectndx);
  352.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  353.           winfo->ep,winfo->mp,VERTS,winfo->ver);
  354.   for (k = 0; k < winfo->count[VERTS]; k++)
  355.     fprintf(oinfo->fp,"%03d %04x %04x\r\n",k,
  356.             (ushort)verts[k].x,(ushort)verts[k].y);
  357.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  358.           winfo->ep,winfo->mp,SEGS,winfo->ver);
  359.   for (k = 0; k < winfo->count[SEGS]; k++)
  360.     fprintf(oinfo->fp,"%03d %04x %04x %04x %04x %04x %04x\r\n",k,
  361.             segs[k].fndx,segs[k].tndx,(ushort)segs[k].angle,
  362.             segs[k].lndx,segs[k].sndx,segs[k].loffset);
  363.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  364.           winfo->ep,winfo->mp,SSECTS,winfo->ver);
  365.   for (k = 0; k < winfo->count[SSECTS]; k++)
  366.     fprintf(oinfo->fp,"%03d %04x %04x\r\n",k,
  367.             ssecs[k].count,ssecs[k].sndx);
  368.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  369.           winfo->ep,winfo->mp,NODES,winfo->ver);
  370.   for (k = 0; k < winfo->count[NODES]; k++)
  371.     fprintf(oinfo->fp,"%03d \
  372. %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x\r\n",k,
  373.             (ushort)nodes[k].x,(ushort)nodes[k].y,
  374.             (ushort)nodes[k].xdel,(ushort)nodes[k].ydel,
  375.             (ushort)nodes[k].rymax,(ushort)nodes[k].rymin,
  376.             (ushort)nodes[k].rxmin,(ushort)nodes[k].rxmax,
  377.             (ushort)nodes[k].lymax,(ushort)nodes[k].lymin,
  378.             (ushort)nodes[k].lxmin,(ushort)nodes[k].lxmax,
  379.             (ushort)nodes[k].nndx[0],(ushort)nodes[k].nndx[1]);
  380.   fprintf(oinfo->fp,"%%\r\n%d %d %d %4.2f\r\n",
  381.           winfo->ep,winfo->mp,SECTS,winfo->ver);
  382.   for (k = 0; k < winfo->count[SECTS]; k++)
  383.     fprintf(oinfo->fp,"%03d %04x %04x %-8.8s %-8.8s %04x %04x %04x\r\n",k,
  384.         (ushort)sects[k].floor_ht,(ushort)sects[k].ceil_ht,
  385.             sects[k].floor_desc,sects[k].ceil_desc,
  386.             sects[k].light_lvl,sects[k].property,(ushort)sects[k].line_tag);
  387.   return TRUE;
  388. }
  389.  
  390.  
  391. /******************************************************************************
  392.     ROUTINE:    wad_open(file,input,rewrite)
  393.     WRITTEN BY:    Robert Fenske, Jr.
  394.     CREATED:    June 1994
  395.     DESCRIPTION:    This routine opens the specified file.  The file is
  396.             created if input and rewrite are FALSE.  If the open
  397.             fails for any reason a NULL is returned, otherwise an
  398.             information block is allocated for the file.  The file
  399.             is identified as either a (P/I)WAD file or a VERDA
  400.             patch file.  If the file is a (P/I)WAD file, then the
  401.             directory is read.  The resource directory is held in
  402.             two locations--one for modification and one to preserve
  403.             the original directory.  The address of the information
  404.             block is returned.
  405. ******************************************************************************/
  406. #if defined(ANSI_C)
  407. WAD_INFO *wad_open(char *file, boolean input, boolean rewrite)
  408. #else
  409. WAD_INFO *wad_open(file,input,rewrite)
  410. char *file;
  411. boolean input, rewrite;
  412. #endif
  413. {
  414.   register FILE *fp;
  415.   register WAD_INFO *winfo;
  416.   register int e;
  417.  
  418.   fp = fopen(file,input?"rb":rewrite?"r+b":"wb");
  419.   if (fp == NULL)                /* oops */
  420.     return NULL;
  421.   winfo = blockmem(WAD_INFO,1);
  422.   if (input || rewrite) {
  423.     rewind(fp);
  424.     fread((char *)&winfo->head,sizeof winfo->head,1,fp);
  425.     if (strncmp(winfo->head.ident,"PWAD",4) == 0 ||
  426.         strncmp(winfo->head.ident,"IWAD",4) == 0) {
  427.       winfo->type = 1;                /* it's a (I/P)WAD */
  428.       winfo->head.count = bswapl(winfo->head.count);
  429.       winfo->head.offset = bswapl(winfo->head.offset);
  430.     }else {
  431.       rewind(fp);
  432.       if (3 == fscanf(fp," %d %d %*d %lf",&winfo->ep,&winfo->mp,&winfo->ver)) {
  433.         winfo->type = 2;            /* it's a patch file */
  434.         winfo->head.count = ALL;
  435.       }else                    /* it's illegal */
  436.         memset(&winfo->head,0,sizeof(winfo->head));
  437.     }
  438.     winfo->origdir = blockmem(DIR_ENTRY,winfo->head.count);
  439.     winfo->dir = blockmem(DIR_ENTRY,winfo->head.count);
  440.     winfo->data = blockmem(char *,winfo->head.count);
  441.     winfo->changed = blockmem(boolean,winfo->head.count);
  442.     winfo->count = blockmem(long,winfo->head.count);
  443.     if (winfo->type == 1) {            /* it's a WAD file */
  444.       rewind(fp);
  445.       fseek(fp,winfo->head.offset,0);        /* read directory */
  446.       fread((char *)winfo->origdir,sizeof(*winfo->origdir),
  447.             (int)winfo->head.count,fp);
  448.     }else if (winfo->type == 2) {        /* it's a patch file */
  449.       if (++winfo->ep != 4)
  450.         sprintf(winfo->origdir[MAINS].name,"E%dM%d",winfo->ep,++winfo->mp);
  451.       else
  452.         sprintf(winfo->origdir[MAINS].name,"MAP%02d",++winfo->mp);
  453.       for (e = 1; e < ALL; e++)
  454.         blockcopy(winfo->origdir[e].name,mapresrc[e],
  455.                   sizeof winfo->origdir[e].name);
  456.     }
  457.     for (e = 0; e < winfo->head.count; e++) {
  458.       winfo->dir[e] = winfo->origdir[e];
  459.       winfo->dir[e].offset =
  460.       winfo->origdir[e].offset = bswapl(winfo->origdir[e].offset);
  461.       winfo->dir[e].nbytes =
  462.       winfo->origdir[e].nbytes = bswapl(winfo->origdir[e].nbytes);
  463.     }
  464.   }
  465.   winfo->fp = fp;
  466.   return winfo;
  467. }
  468.  
  469.  
  470. /******************************************************************************
  471.     ROUTINE:    wad_read(winfo,entry,resources_needed)
  472.     WRITTEN BY:    Robert Fenske, Jr.
  473.     CREATED:    May  1994
  474.     DESCRIPTION:    This routine reads a WAD file. resources_needed governs
  475.             which resources from the level are actually read.
  476. ******************************************************************************/
  477. #if defined(ANSI_C)
  478. boolean wad_read(register WAD_INFO *winfo, int entry, long resources_needed)
  479. #else
  480. boolean wad_read(winfo,entry,resources_needed)
  481. register WAD_INFO *winfo;
  482. int entry;
  483. long resources_needed;
  484. #endif
  485. {
  486.   register int i;
  487.  
  488.   if (winfo == NULL ||
  489.       winfo->fp == NULL) return FALSE;        /* can't do if invalid */
  490.   if (winfo->type == 2)
  491.     return patch_read(winfo,entry,resources_needed);/* do patch file */
  492.   if (winfo->head.count <= entry)        /* can't read beyond count */
  493.     return FALSE;
  494.   for (i = 0; i < sizeof(resources_needed)*8; i++) {
  495.     if (resources_needed & (1L<<i)) {        /* get requested resources */
  496.       blockfree(winfo->data[entry+i]);
  497.       winfo->data[entry+i] = blockmem(char,winfo->origdir[entry+i].nbytes);
  498.       fseek(winfo->fp,winfo->origdir[entry+i].offset,0);
  499.       fread(winfo->data[entry+i],1,(int)winfo->origdir[entry+i].nbytes,
  500.             winfo->fp);
  501. #if defined(BSWAP)
  502.       wad_bswap(winfo,entry+i);
  503. #endif
  504.       winfo->count[entry+i] = resource_count(&winfo->origdir[entry+i]);
  505.     }
  506.   }
  507.   return TRUE;
  508. }
  509.  
  510.  
  511. /******************************************************************************
  512.     ROUTINE:    wad_write(oinfo,winfo)
  513.     WRITTEN BY:    Robert Fenske, Jr.
  514.     CREATED:    May  1994
  515.     DESCRIPTION:    This routine writes a WAD file.  If oinfo has a
  516.             directory then the input file is being rewritten with
  517.             the new data; otherwise, a new file is written.  The
  518.             resources are written out in reverse order; this easily
  519.             handles the case where the input file is being
  520.             rewritten and some of the resources have grown in size.
  521.             Also in the rewrite case, if a resource is smaller than
  522.             before, it is marked with the new smaller size but the
  523.             following resources are not "shifted down".  Thus there
  524.             will be some parts of the file that will be unused.
  525. ******************************************************************************/
  526. #if defined(ANSI_C)
  527. boolean wad_write(register WAD_INFO *oinfo,register WAD_INFO *winfo)
  528. #else
  529. boolean wad_write(oinfo,winfo)
  530. register WAD_INFO *oinfo, *winfo;
  531. #endif
  532. {
  533.   long dir_offset;                /* new directory offset */
  534.   char *buf;                    /* temporary data buffer */
  535.   register int e;
  536.  
  537.   if (oinfo == NULL ||
  538.       oinfo->fp == NULL) return FALSE;        /* can't do if invalid */
  539.   if (oinfo->type == 2)
  540.     return patch_write(oinfo,winfo);        /* do patch file */
  541.   winfo->dir[0].offset = sizeof winfo->head;
  542.   for (e = 1; e < winfo->head.count; e++) {    /* compute new directory */
  543.     if (oinfo->dir == NULL || winfo->origdir[e-1].offset == 0)
  544.       winfo->dir[e].offset = winfo->dir[e-1].offset + winfo->dir[e-1].nbytes;
  545.     else
  546.       winfo->dir[e].offset = winfo->dir[e-1].offset +
  547.                              max(winfo->dir[e-1].nbytes,
  548.                                  winfo->origdir[e].offset-
  549.                                  winfo->origdir[e-1].offset);
  550.   }
  551.   for (e = winfo->head.count-1; e >= 0; e--) {    /* write resources */
  552.     if (winfo->changed[e] || winfo->type == 2) {/* write new data */
  553.       if (winfo->data[e] != NULL) {
  554. #if defined(BSWAP)
  555.         wad_bswap(winfo,e);
  556. #endif
  557.         fseek(oinfo->fp,winfo->dir[e].offset,0);
  558.         fwrite(winfo->data[e],1,(int)winfo->dir[e].nbytes,oinfo->fp);
  559.         blockfree(winfo->data[e]);
  560.         winfo->data[e] = NULL;
  561.       }
  562.     }else if (oinfo->dir == NULL ||
  563.               winfo->origdir[e].offset != winfo->dir[e].offset) {
  564.       buf = blockmem(char,winfo->origdir[e].nbytes);
  565.       fseek(winfo->fp,winfo->origdir[e].offset,0);
  566.       fread(buf,sizeof(*buf),(int)winfo->origdir[e].nbytes,winfo->fp);
  567.       fseek(oinfo->fp,winfo->dir[e].offset,0);
  568.       fwrite(buf,sizeof(*buf),(int)winfo->origdir[e].nbytes,oinfo->fp);
  569.       blockfree(buf);
  570.     }
  571.   }
  572.   dir_offset = winfo->dir[winfo->head.count-1].offset +
  573.                winfo->dir[winfo->head.count-1].nbytes;
  574.   for (e = 0; e < winfo->head.count; e++) {
  575.     winfo->dir[e].offset = bswapl(winfo->dir[e].offset);
  576.     winfo->dir[e].nbytes = bswapl(winfo->dir[e].nbytes);
  577.   }
  578.   fseek(oinfo->fp,dir_offset,0);        /* write new directory */
  579.   fwrite((char *)winfo->dir,sizeof(*winfo->dir),(int)winfo->head.count,
  580.          oinfo->fp);
  581.   for (e = 0; e < winfo->head.count; e++) {
  582.     winfo->dir[e].offset = bswapl(winfo->dir[e].offset);
  583.     winfo->dir[e].nbytes = bswapl(winfo->dir[e].nbytes);
  584.   }
  585.   if (oinfo->dir != NULL)
  586.     blockcopy((char *)winfo->origdir,(char *)winfo->dir,/* this is now       */
  587.               winfo->head.count*sizeof(winfo->dir[0]));/* original directory */
  588.   if (winfo->type == 2) blockcopy(winfo->head.ident,"PWAD",4);
  589.   winfo->head.offset = bswapl(dir_offset);
  590.   winfo->head.count = bswapl(winfo->head.count);
  591.   fseek(oinfo->fp,0L,0);             /* write new header */
  592.   fwrite((char *)&winfo->head,sizeof(winfo->head),1,oinfo->fp);
  593.   winfo->head.offset = bswapl(dir_offset);
  594.   winfo->head.count = bswapl(winfo->head.count);
  595.   return TRUE;
  596. }
  597.  
  598.  
  599. /******************************************************************************
  600.     ROUTINE:    wad_close(winfo)
  601.     WRITTEN BY:    Robert Fenske, Jr.
  602.     CREATED:    June 1994
  603.     DESCRIPTION:    This routine closes the specified file and it frees
  604.             the associated memory.
  605. ******************************************************************************/
  606. #if defined(ANSI_C)
  607. void wad_close(register WAD_INFO *winfo)
  608. #else
  609. void wad_close(winfo)
  610. register WAD_INFO *winfo;
  611. #endif
  612. {
  613.   if (winfo != NULL) {
  614.     if (winfo->fp != NULL) (void)fclose(winfo->fp);
  615.     blockfree(winfo->dir);            /* done with these */
  616.     blockfree(winfo->origdir);
  617.     blockfree(winfo->data);
  618.     blockfree(winfo->changed);
  619.     blockfree(winfo->count);
  620.     blockfree(winfo);
  621.   }
  622. }
  623.